﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Xml;
using Common.Utilities;
using Common.Utilities.Dispatcher;
using Workflows.Components.Entities.Properties;

namespace Workflows.Components.Entities.Providers
{
    [Serializable]
    public class PartitionComponent:WorkflowComponentBase
    {
        #region props
        /// <summary></summary>
        public DataProviderType DbProvider
        {
            get
            {
                return this._Instruction.DbProvider;
            }
            set
            {
                this._Instruction.DbProvider = value;
            }
        }

        /// <summary></summary>
        public string ConnStr
        {
            get
            {
                return this._Instruction.ConnStr;
            }
            set
            {
                this._Instruction.ConnStr = value;
            }
        }

        /// <summary></summary>
        public string SelectSql
        {
            get
            {
                return this._Instruction.SelectSql;
            }
            set
            {
                this._Instruction.SelectSql = value;
            }
        }

        /// <summary></summary>
        public string IdAttributeName
        {
            get
            {
                return this._Instruction.IdAttributeName;
            }
            set
            {
                this._Instruction.IdAttributeName = value;
            }
        }

        /// <summary></summary>
        public string EntityCategory
        {
            get
            {
                return this._Instruction.EntityCategory;
            }
            set
            {
                this._Instruction.EntityCategory = value;
            }
        }

        /// <summary></summary>
        public List<AttributePartition> AttrPartitions
        {
            get
            {
                return this._Instruction.AttrPartitions;
            }
            set
            {
                this._Instruction.AttrPartitions = value;
            }
        }

        /// <summary></summary>
        public int MinCountPerPartition
        {
            get
            {
                return this._Instruction.MinCountPerPartition;
            }
            set
            {
                this._Instruction.MinCountPerPartition = value;
            }
        }

        /// <summary>
        /// <Partitions AttributeName="" BinSize="">
        ///     <Partition PartitionID="1" AttributeValueFrom="" AttributeValueTo="">
        ///         <Entity EntityID="1"/>
        ///     </Partition>
        /// </Partitions>
        /// </summary>
        public string PartitionResultFilePath
        {
            get
            {
                return this._Instruction.PartitionResultFilePath;
            }
            set
            {
                this._Instruction.PartitionResultFilePath = value;
            }
        }

        private PartitionInstruction _Instruction;
        public override InstructionBase Instruction
        {
            get { return _Instruction; }
            set { _Instruction=(PartitionInstruction)value; }
        }

        private PartitionOutput _Output;
        public override ResultBase Output
        {
            get { return _Output; }
            set { _Output = (PartitionOutput)value; }
        }
        #endregion

        public PartitionComponent():base()
        {
            this.ComponentActivityType = WorkflowActivityType.SimpleActivity;
            this.ComponentCategory = WorkflowComponentCategory.Entity_Relations.ToString();
            this.ComponentName = "Partition";
            this.Description = "Partition entities based on attribute values";
            this.ComponentIcon = Resources.DfrgRes_106;
            this.ComponentImage = Resources.defrag;

            this._Instruction =
                new PartitionInstruction(
                    this.ComponentID, Guid.Empty,
                    DataProviderType.MSSQL, string.Empty, string.Empty, 
                    string.Empty, string.Empty,
                    new List<AttributePartition>(), 100, string.Empty);
            this._Output = new PartitionOutput(this.ComponentID, Guid.Empty, 0, 0, string.Empty);
        }

        public override WorkflowComponentBase Instantiate(XmlNode xNode)
        {
            if (xNode.Attributes.GetNamedItem("Type").Value == this.GetType().FullName)
            {
                PartitionComponent component = base.Instantiate(xNode) as PartitionComponent;

                component.IdAttributeName = XmlDataUtil.GetAttributeValue(xNode, "IdAttributeName", "");
                component.EntityCategory = XmlDataUtil.GetAttributeValue(xNode, "EntityCategory", "");


                component.DbProvider =
                    (DataProviderType)
                    int.Parse(XmlDataUtil.GetAttributeValue(xNode, "ProviderDbProvider",
                                                            ((int) DataProviderType.File).ToString()));
                component.ConnStr = XmlDataUtil.GetAttributeValue(xNode, "ProviderConnStr", "");
                component.SelectSql = XmlDataUtil.GetAttributeValue(xNode, "ProviderSelectSql", "");


                // partition 
                XmlNodeList attrPartitionNodes = xNode.SelectNodes("Partitions/Partition");
                if (attrPartitionNodes != null && attrPartitionNodes.Count > 0)
                {
                    component.AttrPartitions = new List<AttributePartition>();
                    foreach (XmlNode attrPartitionNode in attrPartitionNodes)
                    {
                        AttributePartition attrPartition = new AttributePartition();
                        attrPartition.AttributeName = XmlDataUtil.GetAttributeValue(
                            attrPartitionNode, "PartitionAttributeName", "");
                        attrPartition.Method = (PartitionMethod) int.Parse(
                                                                     XmlDataUtil.GetAttributeValue(
                                                                         attrPartitionNode, "PartitionMethod",
                                                                         ((int) PartitionMethod.Percent).ToString()));
                        attrPartition.BinSize =
                            double.Parse(XmlDataUtil.GetAttributeValue(
                                             attrPartitionNode, "PartitionBinSize", "5"));
                        component.AttrPartitions.Add(attrPartition);
                    }
                }
                else
                    component.AttrPartitions = new List<AttributePartition>();

                component.MinCountPerPartition =
                    int.Parse(XmlDataUtil.GetAttributeValue(xNode, "MinCountPerPartition", "100"));


                // result 
                component.PartitionResultFilePath = XmlDataUtil.GetAttributeValue(xNode, "ResultFilePath", "");


                return component;
            }
            else
            {
                throw new Exception("Unable to instantiate email: invalid type specified in xml node");
            }
        }

        public override XmlNode Serialize(ref XmlDocument xDoc, ref XmlNode parentNode)
        {
            XmlNode xNode = base.Serialize(ref xDoc, ref parentNode);

            XmlDataUtil.UpdateAttribute(ref xDoc, xNode, "IdAttributeName", this.IdAttributeName);
            XmlDataUtil.UpdateAttribute(ref xDoc, xNode, "EntityCategory", this.EntityCategory);


            // provider 
            XmlDataUtil.UpdateAttribute(ref xDoc, xNode, "ProviderDbProvider", ((int) this.DbProvider).ToString());
            XmlDataUtil.UpdateAttribute(ref xDoc, xNode, "ProviderConnStr", this.ConnStr);
            XmlDataUtil.UpdateAttribute(ref xDoc, xNode, "ProviderSelectSql", this.SelectSql);

            // partition 
            XmlNode partitionRootNode = XmlDataUtil.AddElement(ref xDoc, xNode, "Partitions");
            if (this.AttrPartitions != null && this.AttrPartitions.Count > 0)
            {
                foreach (AttributePartition attrPartition in this.AttrPartitions)
                {
                    XmlNode partitionNode = XmlDataUtil.AddElement(ref xDoc, partitionRootNode, "Partition");
                    XmlDataUtil.UpdateAttribute(
                        ref xDoc, partitionNode, "PartitionAttributeName",
                        attrPartition.AttributeName);
                    XmlDataUtil.UpdateAttribute(
                        ref xDoc, partitionNode, "PartitionMethod",
                        ((int) attrPartition.Method).ToString());
                    XmlDataUtil.UpdateAttribute(
                        ref xDoc, partitionNode, "PartitionBinSize",
                        attrPartition.BinSize.ToString());
                }
            }

            XmlDataUtil.UpdateAttribute(ref xDoc, xNode, "MinCountPerPartition", this.MinCountPerPartition.ToString());

            // result
            XmlDataUtil.UpdateAttribute(ref xDoc, xNode, "ResultFilePath", this.PartitionResultFilePath);

            return xNode;
        }
    }
}
